package utils

import (
	"bytes"
	"errors"
	"io"
	"mime/multipart"
	"os"
	"path/filepath"

	"go.uber.org/zap"
	"sigs.k8s.io/yaml"
	"xincan.com.cn/tarot-go-framework/global"
)

// UploadConfigClusterServer
// Title    			UploadConfigClusterServer
// Description   		上传集群配置文件, 并修改配置文件中的 server 的值 为 指定的集群地址的值
// Auth      			alittlexincan@163.com         	时间（2024/07/22 11:36）
// Params    			configFile 					文件对象
// Params    			configHeader 				文件头信息
// Params    			clusterId 					集群ID
// Params    			clusterUrl 					集群地址
// Return    			string 						返回文件路径
// Return    			error 						返回错误信息
func UploadConfigClusterServer(configFile multipart.File, configHeader *multipart.FileHeader, clusterId string, clusterUrl string) (string, string, error) {

	defer func(config multipart.File) {
		if err := config.Close(); err != nil {
			global.Logger.Error("关闭文件失败", zap.Error(err))
			return
		}
	}(configFile)

	// 获取文件后缀名
	fileSuffix := filepath.Ext(configHeader.Filename)
	// 判断文件后缀名是否为 yaml 文件或无后缀文本文件
	if fileSuffix != "" && fileSuffix != ".yaml" && fileSuffix != ".conf" {
		global.Logger.Info("文件后缀不正确, 请上传yaml格式的文件或无后缀文本文件", zap.String("fileName", configHeader.Filename))
		return "", "", errors.New("文件格式不正确, 请上传yaml格式的文件或无后缀文本文件")

	}

	// 文件名拼接, 文件名格式为 用户账户-用户上传文件名称
	fileName := clusterId
	// 地址拼接
	filePath := filepath.Join(global.AppConfig.Business.Config, fileName+fileSuffix)
	// 确保文件路径存在（如果需要的话）
	if err := os.MkdirAll(filepath.Dir(filePath), 0755); err != nil {
		global.Logger.Error("创建目录失败", zap.String("filePath", filePath), zap.Error(err))
		return filePath, "", errors.New("创建目录失败, 请检查文件路径是否正确")
	}
	// 判断文件是否存在
	if _, err := os.Stat(filePath); err == nil {
		global.Logger.Info("文件已存在, 请修改文件名称重新上传", zap.String("filePath", filePath))
		return filePath, "", errors.New("文件已存在, 请修改文件名称重新上传")
	}

	// 将file转化为字节
	data, err := io.ReadAll(configFile)
	if err != nil {
		global.Logger.Error("读取文件内容到内存中失败", zap.String("filePath", filePath), zap.Error(err))
		return filePath, "", errors.New("读取文件失败")
	}

	// 解析文件内容, 将集群地址写入到 server 变量中,
	localConfig, err := checkAndSetValueYamlFile(data, clusterUrl)
	if err != nil {
		global.Logger.Error("将文件内容解析到localConfig变量中失败", zap.String("filePath", filePath), zap.Error(err))
		return filePath, "", err
	}

	// 将整个config变量值转化为字节
	data, err = yaml.Marshal(localConfig)
	if err != nil {
		global.Logger.Error("将整个config变量值转化为字节失败", zap.String("filePath", filePath), zap.Error(err))
		return filePath, "", errors.New("将整个config变量值转化为字节失败")
	}
	if err = os.WriteFile(filePath, data, 0644); err != nil {
		global.Logger.Error("回写文件失败", zap.String("filePath", filePath), zap.Error(err))
		return filePath, "", errors.New("回写文件失败")
	}
	return filePath, string(data), nil
}

// checkAndSetValueYamlFile
// Title    			checkAndSetValueYamlFile
// Description   		检查配置文件格式是否正确, 并修改配置文件中 server 的值 为 指定的集群地址的值
// Auth      			alittlexincan@163.com         	时间（2024/07/22 15:38）
// Params    			data 						文件内容
// Params    			clusterUrl 					集群地址
// Return    			map[string]interface{} 		返回文件内容
// Return    			error 						返回错误信息
func checkAndSetValueYamlFile(data []byte, clusterUrl string) (map[string]interface{}, error) {
	var localConfig map[string]interface{}
	if err := yaml.Unmarshal(data, &localConfig); err != nil {
		return nil, errors.New("解析文件内容失败")
	}

	clusters, ok := localConfig["clusters"].([]interface{})
	if !ok {
		global.Logger.Error("配置文件格式不正确，缺少clusters字段或字段类型不正确")
		return nil, errors.New("配置文件格式不正确")
	}
	if len(clusters) == 0 {
		global.Logger.Error("配置文件中的clusters字段为空")
		return nil, errors.New("配置文件中的clusters字段为空")
	}
	clusterMap, ok := clusters[0].(map[string]interface{})
	if !ok {
		global.Logger.Error("配置文件中的clusters字段的第一个元素类型不正确")
		return nil, errors.New("配置文件中的clusters字段的第一个元素类型不正确")
	}
	serverMap, ok := clusterMap["cluster"].(map[string]interface{})
	if !ok {
		global.Logger.Error("配置文件中的cluster字段不存在或类型不正确")
		return nil, errors.New("配置文件中的cluster字段不存在或类型不正确")
	}
	serverMap["server"] = clusterUrl
	return localConfig, nil
}

// GetFileContent
// Title    			GetFileContent
// Description   		获取文件内容
// Auth      			alittlexincan@163.com         	时间（2024/07/22 15:38）
// Params    			uri 						文件路径
// Return    			string 					返回文件内容
// Return    			error 					返回错误信息
func GetFileContent(uri string) (string, error) {

	// 获取文件内容
	file, err := os.Open(uri)
	if err != nil {
		global.Logger.Error("打开文件失败", zap.String("filePath", uri), zap.Error(err))
		return "", err
	}
	defer func(file *os.File) {
		err := file.Close()
		if err != nil {
			global.Logger.Error("关闭文件失败", zap.String("filePath", uri), zap.Error(err))
		}
	}(file)

	// 创建一个缓冲区来读取文件内容
	var buf bytes.Buffer

	// 将文件内容复制到缓冲区中
	_, err = io.Copy(&buf, file)
	if err != nil {
		global.Logger.Error("读取文件内容失败", zap.String("filePath", uri), zap.Error(err))
		return "", err
	}

	// 将缓冲区的内容转换为字符串并返回
	return buf.String(), nil
}

// CreateNacosFile
// Title    			CreateNacosFile
// Description   		创建nacos日志文件
// Auth      			alittlexincan@163.com         	时间（2024/07/22 15:38）
// Params    			globalDir 						全局配置路径
// Params    			nacosLogDir 					日志配置路径
// Params    			serviceName 					服务名称
// Return    			string 						返回日志文件路径

func CreateNacosFile(globalDir string, nacosLogDir string, serviceName string) (string, error) {
	var logDir string
	// 判断日志配置路径是否存在
	if nacosLogDir != "" {
		logDir = nacosLogDir
	} else {
		logDir = globalDir + "/" + serviceName + "/nacos"
	}

	absPath, err := filepath.Abs(logDir)
	if err != nil {
		return "", err
	}

	// 使用os.MkdirAll来创建目录，如果目录已存在则不会报错
	if err := os.MkdirAll(absPath, 0755); err != nil {
		return "", err
	}
	return logDir, nil
}

// CreateFile
// Title    			CreateFile
// Description   		创建文件
// Auth      			alittlexincan@163.com         	时间（2024/07/22 15:38）
// Params    			filePath 						文件路径
// Return    			error 						返回错误信息
func CreateFile(filePath string) error {
	absPath, _ := filepath.Abs(filePath)
	err := os.MkdirAll(absPath, 0755)
	if err != nil {
		global.Logger.Error("创建文件失败", zap.String("filePath", filePath), zap.Error(err))
		return errors.New("创建文件失败")
	}
	return nil
}
